home *** CD-ROM | disk | FTP | other *** search
- ; XFLASH by David Hite - Optimized for 8088 Processor
- ; Eliminates the flash that occurs during scrolling on the CGA.
- ; XFLASH is FreeWare.
-
- ; Your machine may be able to move more characters or fewer
- ; characters during vertical retraces than mine.
- ; You can experiment by changing the values of max_vert and clr_max_vert.
- ; Max_horiz will probably not need to be changed, because it is
- ; based on the CGA's 200 scan lines.
-
- ; The difference between XFLASH and XFLASH-2, other than the different
- ; values for max_vert and clr_max_vert, is that XFLASH-2 moves a word
- ; during the horizontal retrace, while XFLASH can only move a byte.
- ; The code is therefore slightly different.
-
- clr_max_vert equ 420 ; the maximum number of words to
- ; clear during a vertical retrace
- max_vert equ 210 ; the maximum number of words to move in
- ; a vertical retrace
- max_horiz equ 196 ; must be an even number!
- ; the maximum number of horizontal retraces
- ; to be used for moving 1 byte between
- ; vertical retraces. This is set to just
- ; less than the number of scan lines so that
- ; the next vertical retrace is not missed.
- ; Increasing this value can actually slow the
- ; program down because it will have to wait
- ; longer for the next vertical retrace.
-
- vstat equ 3dah ; the video status register
- v_retrace equ 00001000b ; vertical retrace bit mask
- h_retrace equ 00000001b ; horizontal retrace bit mask
-
-
- cseg segment para public 'code'
- assume cs:cseg,ds:cseg,ss:cseg,es:nothing
- org 100h
-
- start:
- jmp install ; install the program
-
- savestack dw 0,0
- request dw 0 ; ax from interrupt
- fill_attrib dw 0 ; bx from interrupt
- video_handler dd 0 ; address of the original video handler
- apage db 0 ; active video page
- amode db 3 ; active video mode
- display_seg dw 0b800h ; addr of cga display memory
-
- new_video_int proc far ; far label since it's entered by interrupt
- ; and thus must generate inter-segment ret
- sti ; enable interrupts
-
- cmp ah,0 ; check for mode switch
- jne chk_mode
- mov cs:amode,al ; remember new mode
- jmp short not_ours ; and let bios change the mode
-
- chk_mode:
- cmp cs:amode,3 ; we don't scroll graphics modes
- jg not_ours
-
- chk_5:
- cmp ah,5 ; check for page switch
- jl not_ours
- jne chk_6
- mov cs:apage,al ; remember new page number
- jmp short not_ours ; and let bios change the page
-
- chk_6:
- cmp ah,6
- jne chk_7
- chk_6a:
- cmp cl,0 ; we do it only for complete lines
- jne not_ours
- cmp dl,79
- jne not_ours
- jmp short scroll
-
- chk_7:
- cmp ah,7
- je chk_6a
-
- not_ours:
- pushf ; emulate int instruction
- call dword ptr [cs:video_handler]
- iret
-
- scroll:
- mov cs:savestack,sp
- mov cs:savestack+2,ss
-
- mov cs:request,ax
- mov ax,cs
- mov ss,ax
- mov sp,100h
-
- push bp ; set up a stack frame
- mov bp,sp
- sub sp,0eh
- call savereg
- mov ds,ax
- mov ax,request
-
- call main ; that's where the work is done
-
- call restreg
- add sp,0eh
- pop bp
-
- mov ss,cs:savestack+2
- mov sp,cs:savestack
-
- iret ; return from interrupt
-
- new_video_int endp
-
- inside proc near
- fix_ch0:
- mov ch,0
- jmp short chk_dh
- fix_ch24:
- mov ch,24
- jmp short chk_dh
- fix_dh0:
- mov dh,0
- jmp short chk_al
- fix_dh24:
- mov dh,24
- jmp short chk_al
- fix_al25:
- mov al,25
- jmp short regs_ok
-
- main:
- mov fill_attrib,bx ; save fill attribute for much later (clr_area)
- push dx ; because MUL uses it
- cmp ch,0
- jl fix_ch0
- cmp ch,24
- jg fix_ch24
- chk_dh:
- cmp dh,0
- jl fix_dh0
- cmp dh,24
- jg fix_dh24
- chk_al:
- mov ax,request
- cmp al,0
- jle fix_al25
- cmp al,25
- jg fix_al25
- regs_ok:
- mov request,ax ; in case we fixed it
- xor bh,bh
- mov bl,apage ; get the current page number
- mov ax,4096 ; the size of a a page
- mul bx ; multiply by the page number to get offset
- mov di,ax ; and put it in the destination index
- ; now calculate the offset of the window
- mov bl,ch ; by getting the starting row
- xor bh,bh
- mov ax,160 ; we only handle full rows
- mul bx ; and multiply by chars/row to get offset
- add di,ax ; and adding to di to get address
- mov ax,di
- mov si,ax ; and put it in the source index as well
- pop dx
- mov ax,request ; get the original request
- mov bh,dh ; move bottom line to bh
- sub bh,ch ; subtract top line
- inc bh ; bh now has number of lines in window
-
- cld ; we'll move forward unless scroll is down
- mov es,display_seg
- cmp al,0 ; clear the area?
- jbe m_1 ; yes
- cmp al,bh
- je m_1b ; we are clearing all the lines
- jb m_2 ; we are clearing some of the lines
- m_1: ; we are clearing more than all the lines!
- mov al,bh ; move number of lines in window to al
- mov request,ax
- m_1b:
- jmp clr_area
-
- m_2: ; bh has lines in window, al has lines
- ; to scroll
- cmp ah,6 ; up or down?
- je up
- down: ; we are scrolling down
- std ; so we move backwards
-
- sub al,bh ; the source is bh-al lines below si
- neg al ; correct the sign
- cbw ; convert to a word
- mov cx,160
- mul cx ; multiply by chars/row
- sub ax,2 ; subtract a word to get end of line
- add si,ax ; and add to si, the address of the up left
-
- ; the destination is the lower right which is bh lines
- ; below current di => di = di + bh*160 - 2
-
- mov al,bh ; get lines in window into al
- cbw
- mov cx,160
- mul cx
- sub ax,2 ; subtract a word to get end of line
- add di,ax ; di now has address of destination
-
- jmp short movem
-
- up: ; we are scrolling up
- ; the source is al lines below si which is al*160 chars below current si
-
- cbw ; gets number of lines into ax
- mov cx,160
- mul cx
- add si,ax ; si now has address of source
-
- ; the initial destination is correct, we don't need to change it
-
- movem: ; now start to move words
- ; fix bx such that it is number of words to move
- ; = (number of lines in window minus number of lines to scroll)*80
-
- mov ax,request ; get number of lines to scroll
- cbw ; slightly faster than xor ah,ah
- sub al,bh ; subtract lines in window from lines to scroll
- neg al ; after correcting the sign, ax has lines to move
- mov cx,80 ; words/line
- mul cx ; multiply to get words to move
- mov bx,ax ; bx now has number of words to move
-
- push ds ; we're about to change it to display_seg
- mov dx,vstat ; the video status register
- mov ds,display_seg ; load address of display segment
-
- mvm_vert: ; first wait for a vertical refresh
- mov cx,bx ; move words remaining to cx
- cmp cx,max_vert ; too many?
- jle mvm_many ; no, go move'm
- mov cx,max_vert ; yes, move max_vert more, maximum
- mvm_many:
- sub bx,cx ; that many will remain when rep movsw ends
-
- mvm_v_refresh:
- in al,dx
- test al,v_retrace
- jnz mvm_v_refresh ; wait for a non retrace period
-
- mvm_v_wait:
- in al,dx ; get the retrace status
- test al,v_retrace ; check for retrace in progress
- jz mvm_v_wait ; wait until retrace
-
- ; in a vertical retrace, we can move many
- rep movsw
- cmp bx,0
- je mvm_end
-
- mov cx,max_horiz
- shl bx,1 ; to convert words to bytes
- mvm_1:
- dec bx
- mvm_h_refresh:
- in al,dx
- test al,h_retrace
- jnz mvm_h_refresh ; wait for a non retrace period
-
- ; the next statement is commented out to prevent comm char loss
- ; cli ; disable interrupts while waiting (not long)
- mvm_h_wait:
- in al,dx ; get the retrace status
- test al,h_retrace ; check for retrace in progress
- jz mvm_h_wait ; wait until retrace
-
- movsb ; now move one byte
- ; sti ; and now enable interrupts again
-
- cmp bx,0 ; are we finished?
- je mvm_end
- loop mvm_1 ; only if cx not 0
- cmp bx,0
- je mvm_end
-
- mvm_do_cx_again:
- shr bx,1 ; convert back to words
- mov cx,bx ; move words remaining to cx
- cmp cx,max_vert ; too many?
- jle mvm_h_many ; no, go move'm
- mov cx,max_vert ; yes, move max_vert more, maximum
- mvm_h_many:
- sub bx,cx ; that many will remain when rep movsw ends
- jmp mvm_v_wait
-
- mvm_end: ; we've finished moving
- pop ds ; restore the data segment
-
- clr_area:
- ; we're now ready to blank the number of lines that were scrolled.
- ; The direction flag and di and es are set correctly, given
- ; what we've done so far. All we need to do is calculate number of
- ; words to blank.
-
- mov ax,request ; to get number lines to scroll
- cbw
- mov cx,80 ; words/line
- mul cx ; ax now has words to blank
- mov bx,ax ; put it in bx
-
- mov dx,fill_attrib ; dh now has the fill attribute
- mov dl,' ' ; move a space to dl
-
- mov si,dx ; move clear char to si
-
- ; the following code sets the screen border to the fill attribute.
- ; un-comment it if you want to do this
- ; mov cl,4
- ; shr dh,cl
- ; mov al,dh
- ; or al,20h
- ; mov dx,03d9h ; set border to fill attribute
- ; out dx,al
- ; end of set border code
-
- mov dx,vstat ; the video status register
-
- clr_vert: ; first wait for a vertical refresh
- mov cx,bx ; move words remaining to cx
- cmp cx,clr_max_vert ; too many?
- jle clr_many ; no, go move'm
- mov cx,clr_max_vert ; yes, move clr_max_vert more, maximum
- clr_many:
- sub bx,cx ; that many will remain when rep stosw ends
-
- clr_v_refresh:
- in al,dx
- test al,v_retrace
- jnz clr_v_refresh ; wait for a non retrace period
-
- clr_v_wait:
- in al,dx ; get the retrace status
- test al,v_retrace ; check for retrace in progress
- jz clr_v_wait ; wait until retrace
- xchg ax,si
- rep stosw
- xchg ax,si
- cmp bx,0
- je clr_end
-
- mov cx,max_horiz
- clr_1:
- dec bx
- clr_h_refresh:
- in al,dx
- test al,h_retrace
- jnz clr_h_refresh ; wait for a non retrace period
-
- ; the next statement is commented out to prevent comm char loss
- ; cli ; disable interrupts while waiting (not long)
- clr_h_wait:
- in al,dx ; get the retrace status
- test al,h_retrace ; check for retrace in progress
- jz clr_h_wait ; wait until retrace
- xchg ax,si
- stosw ; now move one word
- ; sti ; and now enable interrupts again
- xchg ax,si
- cmp bx,0 ; are we finished?
- je clr_end
- loop clr_1
- cmp bx,0
- je clr_end
-
- clr_do_cx_again:
- mov cx,bx ; move words remaining to cx
- cmp cx,clr_max_vert ; too many?
- jle clr_h_many ; no, go move'm
- mov cx,clr_max_vert ; yes, move clr_max_vert more, maximum
- clr_h_many:
- sub bx,cx ; that many will remain when rep movsw ends
- jmp clr_v_wait
-
- clr_end: ; we've finished moving
-
- cld ; just for the heck of it
- ret
-
-
- savereg:
- mov -2[bp],bx
- mov -4[bp],cx
- mov -6[bp],dx
- mov -8[bp],si
- mov -0ah[bp],di
- mov -0ch[bp],ds
- mov -0eh[bp],es
- ret
- restreg:
- mov bx,-2[bp]
- mov cx,-4[bp]
- mov dx,-6[bp]
- mov si,-8[bp]
- mov di,-0ah[bp]
- mov ds,-0ch[bp]
- mov es,-0eh[bp]
- ret
- inside endp
-
- install:
-
- mov ax,3510h ; get interrupt 10 vector
- int 21h
- mov word ptr video_handler,bx
- mov word ptr video_handler+2,es
-
- mov ax,2510h
- mov dx,offset new_video_int ; now put our routine there
- int 21h
-
- mov dx,offset install ; terminate and stay resident
- mov cl,4
- shr dx,cl
- inc dx ; round up
- mov ah,31h
- int 21h
-
-
- cseg ends
- end start
-